package com.example.mq.server.core;

import com.example.mq.common.MqException;

public class Router {
    // bindingKey的构造规则
    // 数字，字母，*，#用.分割
    // aaa.bbb.ccc
    // aaa.*.ccc
    // aaa.#.ccc
    public boolean checkBindingKey(String bindingKey) {
        if (bindingKey.length() == 0) {
            // 交换机可以不添加绑定关系
            return true;
        }
        for (int i = 0; i < bindingKey.length(); i++) {
            char ch = bindingKey.charAt(i);
            if (ch >= 'A' && ch <= 'Z') {
                continue;
            }
            if (ch >= 'a' && ch <= 'z') {
                continue;
            }
            if (ch >= '0' && ch <= '9') {
                continue;
            }
            if (ch == '.' || ch == '#' || ch == '*' || ch == '_') {
                continue;
            }
            return false;
        }
        // 检查*，#是否是独立的部分
        String[] words = bindingKey.split("\\.");
        for (String word : words) {
            if (word.length() > 1 && (word.contains("*") || word.contains("#"))) {
                return false;
            }
        }
        // 约定*，#的出现规则
        for (int i = 0; i < words.length - 1; i++) {
            if (words[i].equals("#") && words[i+1].equals("#")) {
                return false;
            }
            if (words[i].equals("#") && words[i+1].equals("*")) {
                return false;
            }
            if (words[i].equals("*") && words[i+1].equals("#")) {
                return false;
            }
        }
        return true;
    }

    // routingKey的构造规则
    // 1.数字,字母,下划线 .
    public boolean checkRoutingKey(String routingKey) {
        if (routingKey.length() == 0) {
            // 没有直接通过，fanout/direct这种可以不设置匹配关系
            return true;
        }
        for (int i = 0; i < routingKey.length(); i++) {
            char ch = routingKey.charAt(i);
            if (ch >= 'A' && ch <= 'Z') {
                continue;
            }
            if (ch >= 'a' && ch <= 'z') {
                continue;
            }
            if (ch >= '0' && ch <= '9') {
                continue;
            }
            if (ch == '.' || ch == '_') {
                continue;
            }
            return false;
        }
        return true;
    }

    public boolean route(ExchangeType exchangeType, Binding binding, Message message) throws MqException {
        if (exchangeType == ExchangeType.FANOUT) {
            return true;
        } else if (exchangeType == ExchangeType.TOPIC) {
            return routeTopic(binding, message);
        } else {
            throw new MqException("[Router] 交换机类型非法！exchangeType = " +exchangeType);
        }
    }

    private boolean routeTopic(Binding binding, Message message) {
        // 匹配算法，topic的匹配规则
        String[] bindingTokens = binding.getBindingKey().split("\\.");
        String[] routingTokens = message.getRoutingKey().split("\\.");
        int bindingIndex = 0;
        int routingIndex = 0;
        while (bindingIndex != bindingTokens.length && routingIndex != routingTokens.length) {
            // 判断*号，如果bindingKey中有*号,routingKey直接跳过这个部分
            if (bindingTokens[bindingIndex].equals("*")) {
                bindingIndex++;
                routingIndex++;
            } else if (bindingTokens[bindingIndex].equals("#")) {
                bindingIndex++;
                if (bindingIndex == bindingTokens.length) {
                    // #号后面可以匹配所有，直接返回即可
                    return true;
                }
                // #号后面还有，则利用后面的这个进行查找
                routingIndex = findNextMatch(routingTokens, routingIndex, bindingTokens[bindingIndex]);
                if (routingIndex == -1) {
                    // 没有找到，说明不匹配
                    return false;
                }
                // 找到了则继续匹配
                bindingIndex++;
                routingIndex++;
            } else {
                // 如果这个部分是普通情况直接比较
                if (!bindingTokens[bindingIndex].equals(routingTokens[routingIndex])) {
                    return false;
                }
                bindingIndex++;
                routingIndex++;
            }
        }
        return bindingIndex == bindingTokens.length && routingIndex == routingTokens.length;
    }

    private int findNextMatch(String[] routingTokens, int routingIndex, String bindingToken) {
        while (routingIndex != routingTokens.length) {
            if (routingTokens[routingIndex].equals(bindingToken)) {
                return routingIndex;
            }
            routingIndex++;
        }
        return -1;
    }
}
